package com.seanLab.service;

import com.google.gson.Gson;
import com.seanLab.configuration.ModelConfig;
import com.seanLab.configuration.StaticConfig;
import com.seanLab.domain.*;
import com.seanLab.dto.*;
import com.seanLab.repository.EditorSessionRepo;
import com.seanLab.repository.ImageRepo;
import com.seanLab.tool.ExpertsSuggestor;
import com.seanLab.tool.TagSuggestor;
import com.seanLab.tool.es.ESImageSearch;
import com.seanLab.util.TopicPair;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.*;

/**
 * Created by ailly on 17-9-21.
 */
@Service
public class RecommendService {
    @Autowired
    private ImageRepo imageRepo;

    @Autowired
    private EditorSessionRepo editorSessionRepo;

    @Autowired
    private ESImageSearch esImageSearch;

    @Autowired
    private TagSuggestor tagSuggestor;

    @Autowired
    private ExpertsSuggestor expertsSuggestor;

    @Autowired
    private ModelConfig modelConfig;

    @Value("${com.dasLab.es.resultNum}")
    private int coverNum;

    private static Logger logger = LogManager.getLogger(RecommendService.class);
    private static Logger recommendLogger = LogManager.getLogger("recommendLog");

    @PostConstruct
    public void init() {
        this.esImageSearch.initConnection();
        this.tagSuggestor.loadModel(modelConfig.getModelPath());
        this.tagSuggestor.loadLdaModel(modelConfig.getLdaModelPath());
    }

    public Body recommendImages(RecommendArticleDto recommendArticleDto){

        long start = System.currentTimeMillis();
        // *** Phrase 1: 抽取关键词和主题

        // 抽取文章关键词
        List<SuggestArticleKeywordsDto> keywords = this.tagSuggestor.doSuggest(recommendArticleDto);
        // 抽取文章主题
        List<Double> tmp_topics = this.tagSuggestor.doTopics(recommendArticleDto.getContent());
        // 计算top主题，取前10个
        List<Integer> tmp_topTopics = TopicPair.getTopTopics(tmp_topics);

        long end0 = System.currentTimeMillis();
        // *** Phrase 2: 根据关键词推荐图片

        // 新闻图库推荐 5张
        List<RecommendImageDto> recommendImageList = this.getRecommendImageList(keywords, tmp_topTopics);
        if (recommendImageList.size() > 5) {
            recommendImageList = recommendImageList.subList(0, 5);
        }

        // 专题图库推荐 1张
        List<RecommendImageDto> recommendImageListFromWiki = esImageSearch.searchByKeywordsFromWiki(keywords, 1);

        // 策略图库推荐 1张
        RecommendImageDto recommendImageDtoFromExpert = expertsSuggestor.recommendImage(recommendArticleDto.getTitle(), recommendArticleDto.getCategoryInt());

        RecommendImageListDto recommendImageListDto = new RecommendImageListDto();

        String sessionID = "sessionID-" + UUID.randomUUID().toString();
        recommendImageListDto.setSessionID(sessionID);

        // 策略图库(1)+专题图库(1)+新闻图库(5)
        List<RecommendImageDto> integrateImageList = new ArrayList<>();
        if (recommendArticleDto.isFilter_outer_domain()) {
            //新闻图库优先（过滤外部图片时）
            integrateImageList.addAll(recommendImageList);
        }
        if (recommendImageDtoFromExpert != null) {
            //策略图库
            integrateImageList.add(recommendImageDtoFromExpert);
        }
        // 只有财经(1)和科技(2)类采用专题图库
        if (recommendArticleDto.getCategoryInt() == 1 || recommendArticleDto.getCategoryInt() == 2) {
            //专题图库
            integrateImageList.addAll(recommendImageListFromWiki);
        }
        if (!recommendArticleDto.isFilter_outer_domain()) {
            //新闻图库最后，不过滤外部图片时
            integrateImageList.addAll(recommendImageList);
        }

        recommendImageListDto.setImgList(integrateImageList);

        //反馈抽取出的keywords
        ArrayList<String> stumpkeywords= new ArrayList<>();
        for (SuggestArticleKeywordsDto k : keywords) {
            stumpkeywords.add(k.getKeywords());
        }
        recommendImageListDto.setKeywords(stumpkeywords);

        long end1 = System.currentTimeMillis();
        // *** Phrase 3: 持久化editorSession表（记录采纳了推荐了哪些图片 id）

        EditorSession editorSession = saveEditorSession(sessionID, recommendArticleDto, keywords, recommendImageListDto);
        // 处理时间
        editorSession.setProcessTime(end1 - start);
        this.editorSessionRepo.save(editorSession);

        long end2 = System.currentTimeMillis();
        // *** Phrase 4: 返回结果
        Body body = Body.getResponseBody(0, recommendImageListDto);
        logger.info(recommendArticleDto.getTitle() + " category: " + recommendArticleDto.getCategory() + " suggest time: " + (end0 - start) + " query time: " + (end1 - end0) + " log time: " + (end2 - end1) + " all time: " + (end2 - start));

        recommendLogger.info(new Gson().toJson(editorSession));
        return body;
    }

    private EditorSession saveEditorSession(String sessionID,
                                            RecommendArticleDto recommendArticleDto,
                                            List<SuggestArticleKeywordsDto> keywords,
                                            RecommendImageListDto recommendImageListDto) {
        EditorSession editorSession = new EditorSession();
        editorSession.setSessionID(sessionID);
        editorSession.setContent(recommendArticleDto.getContent());
//        editorSession.setKeywords(new ArrayList<>(uniqueKeywords));
        editorSession.setArticleCategory(recommendArticleDto.getCategoryInt());
        editorSession.setKeywords(keywords);
        editorSession.setTitle(recommendArticleDto.getTitle());
        editorSession.setUrl(recommendArticleDto.getUrl());
        editorSession.setRecommendDate(new Date());

        //推荐指标相关字段

        editorSession.initInnerImg();

        List<String> tmpSessionRecImgs = new ArrayList<>();
        for (RecommendImageDto i : recommendImageListDto.getImgList()) {
            //imageID
            tmpSessionRecImgs.add(i.getImgID());

            //tagIDs
            List<String> ids = new ArrayList<>();
            for (RecommendTagInfoDto rt : i.getImgTagList() ) {
                ids.add(rt.getTagID());
            }

            //tagNames
            List<String> names = new ArrayList<>();
            for (RecommendTagInfoDto rt : i.getImgTagList() ) {
                names.add(rt.getTagName());
            }
            //new setter
            editorSession.addInnerImg(i.getImgID(), ids, names, i.getImgScore(), i.getImgOriginalURL());
        }
        editorSession.setRecommendedImgs(tmpSessionRecImgs);

        //testLabel
        editorSession.setTestLabel(StaticConfig.recommendLabel);

        //覆盖率策略
        if (tmpSessionRecImgs.size() >= (coverNum / 2) ) {
            editorSession.setCoverFlag(1);
        }
        return editorSession;
    }

    private List<RecommendImageDto> getRecommendImageList(List<SuggestArticleKeywordsDto> keywords, List<Integer> tmp_topTopics) {
        ESImageSearch esImageSearch = this.esImageSearch;
        //抽取出的图片
        //es 搜索策略
        List<RecommendImageDto> recommendImageList;

        if (StaticConfig.topicFilter.equals("True")) {
            if (tmp_topTopics.get(0) == 0 && tmp_topTopics.get(1) == 1) {
                recommendImageList = esImageSearch.searchByKeywordsWithWeight(keywords);
//                recommendImageList = esImageSearch.searchByKeywords(stumpkeywords);
//                recommendImageList = esImageSearch.searchByKeywordsWithScore(keywords);
            } else {
//                recommendImageList = esImageSearch.searchByKeywordsAndFilters(stumpkeywords, tmp_topTopics);
                recommendImageList = esImageSearch.searchByKeywordsWithWeight_TopicFilter(keywords, tmp_topTopics);

            }
        } else {
//            recommendImageList = esImageSearch.searchByKeywords(stumpkeywords);
            recommendImageList = esImageSearch.searchByKeywordsWithWeight(keywords);

        }

        //图片去重，同时过滤gif
        Map<String, RecommendImageDto> imageMap_url = new LinkedHashMap<>();
        for (RecommendImageDto tmpImageDto : recommendImageList) {
            //过滤gif
            if (!tmpImageDto.getImgOriginalURL().endsWith("gif") && !tmpImageDto.getImgOriginalURL().endsWith("GIF")) {
                //图片去重
                if (!imageMap_url.containsKey(tmpImageDto.getImgOriginalURL())) {
                    imageMap_url.put(tmpImageDto.getImgOriginalURL(), tmpImageDto);
                }
            }
            if (imageMap_url.size() == coverNum / 2) {
                break;
            }
        }

        int duplicateNum = 2;

        List<RecommendImageDto> resList = new ArrayList<>();

        //根据article_id去重
        Map<String, Integer> imageMap_articleID = new HashMap<>();
        for (RecommendImageDto tmpImageDto : new ArrayList<>(imageMap_url.values())) {
            String id = tmpImageDto.getArticleID();
            int count = imageMap_articleID.getOrDefault(id, 0);
            if (count < duplicateNum) {
                resList.add(tmpImageDto);
            }
            imageMap_articleID.put(id, ++count);
        }

        return resList;
    }

}
